package com.zxy.supplier_system.server.repository

import com.zxy.supplier_system.server.entity.ProcurementReceipt
import com.zxy.supplier_system.server.entity.ProcurementReceiptItem
import com.zxy.supplier_system.server.entity.ProcurementSupplier
import com.zxy.supplier_system.server.entity.SystemService
import com.zxy.supplier_system.server.utils.SpecificationUtils
import com.zxy.supplier_system.server.utils.joinOnce
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.domain.Specification
import org.springframework.data.jpa.repository.JpaRepository
import java.time.OffsetDateTime
import java.time.YearMonth
import java.time.ZoneId

@Suppress("FunctionName")
interface ProcurementReceiptItemRepository : JpaRepository<ProcurementReceiptItem, Int> {

    fun findAllByProcurementReceipt_IdOrderBySequence(
        procurementReceipt_id: Int,
        pageable: Pageable
    ): Page<ProcurementReceiptItem>

    fun findByProcurementReceipt_IdAndGoods_IdAndGoods_SystemService(
        procurementReceipt_id: Int, goods_id: Int, goods_systemService: SystemService
    ): ProcurementReceiptItem?

    fun existsByProcurementReceipt_IdAndGoods_Id(procurementReceipt_id: Int, goods_id: Int): Boolean

    fun existsByProcurementReceipt_IdAndGoods_Barcode(procurementReceipt_id: Int, goods_barcode: String): Boolean

    fun findByProcurementReceipt_IdAndGoods_IdAndSubGoods_IdAndProcurementReceipt_CreatedBy_SystemService(
        procurementReceipt_id: Int, goods_id: Int, subGoodsId: Int, goods_systemService: SystemService
    ): ProcurementReceiptItem?

    fun findFirstByProcurementReceipt_Supplier_IdAndGoods_IdOrderByProcurementReceipt_CreatedDateTimeDesc(
        market_id: Int,
        goods_id: Int
    ): ProcurementReceiptItem?

    fun findFirstByProcurementReceipt_Supplier_IdAndGoods_IdAndSubGoods_IdOrderByProcurementReceipt_CreatedDateTimeDesc(
        market_id: Int,
        goods_id: Int,
        subGoods_id: Int
    ): ProcurementReceiptItem?


    object Specifications{
        fun procurementValidated(): Specification<ProcurementReceiptItem> {
            return Specification { root, query, cb ->
                cb.isNotNull(
                    root.joinOnce<ProcurementReceiptItem, ProcurementReceipt>("procurementReceipt").get<OffsetDateTime>("validatedDateTime")
                )
            }
        }

        fun systemServiceEqual(systemService: SystemService): Specification<ProcurementReceiptItem> {
            return SystemServiceRepository.Specifications.systemServiceEquals({ root ->
                root.joinOnce<ProcurementReceiptItem, ProcurementReceipt>("procurementReceipt").joinOnce("supplier")
            }, systemService)
        }

        fun supplierIdEqual(supplierId: Int?): Specification<ProcurementReceiptItem> {
            return if (supplierId == null) SpecificationUtils.empty()
            else Specification { root, query, cb ->
                cb.equal(
                    root.joinOnce<ProcurementReceiptItem, ProcurementReceipt>("procurementReceipt")
                        .joinOnce<ProcurementReceipt, ProcurementSupplier>("supplier").get<Int>("id"), supplierId
                )
            }
        }

        fun createdDateTimeBefore(dateTime: OffsetDateTime?): Specification<ProcurementReceiptItem> {
            return if (dateTime == null) SpecificationUtils.empty()
            else Specification { root, query, cb ->
                cb.lessThanOrEqualTo(
                    root.joinOnce<ProcurementReceiptItem, ProcurementReceipt>("procurementReceipt")
                        .get<OffsetDateTime>("createdDateTime"),
                    dateTime
                )
            }
        }

        fun createdDateTimeLessThanOrEqual(yearMonth: YearMonth?): Specification<ProcurementReceiptItem> {
            return if (yearMonth == null) SpecificationUtils.empty()
            else Specification { root, query, cb ->
                cb.lessThan(
                    root.joinOnce<ProcurementReceiptItem, ProcurementReceipt>("procurementReceipt")
                        .get<OffsetDateTime>("createdDateTime"),
                    yearMonth.atEndOfMonth().plusDays(1).atStartOfDay()
                        .atOffset(OffsetDateTime.now(ZoneId.systemDefault()).offset)
                )
            }
        }

        fun createdDateTimeGreatThanOrEqual(yearMonth: YearMonth?): Specification<ProcurementReceiptItem> {
            return if (yearMonth == null) SpecificationUtils.empty()
            else Specification { root, query, cb ->
                cb.greaterThanOrEqualTo(
                    root.joinOnce<ProcurementReceiptItem, ProcurementReceipt>("procurementReceipt")
                        .get<OffsetDateTime>("createdDateTime"),
                    yearMonth.atDay(1).atStartOfDay()
                        .atOffset(OffsetDateTime.now(ZoneId.systemDefault()).offset)
                )
            }
        }

        fun systemServiceEquals(systemService: SystemService):Specification<ProcurementReceiptItem> {
            return SystemServiceRepository.Specifications.systemServiceEquals({ r->r.joinOnce<ProcurementReceiptItem, ProcurementReceipt>("procurementReceipt").joinOnce<ProcurementReceipt, ProcurementSupplier>("supplier")},systemService)
        }
    }
}
